package cn.middle.swap.config;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import cn.middle.remote.Buffer;
import cn.middle.remote.Server;
import cn.middle.remote.functions.CallbackEvent;
import cn.middle.remote.functions.PushEventFunction;
import cn.middle.remote.serialization.TypeGenericity;
import cn.middle.remote.server.LoginAuthHandler;
import cn.middle.remote.server.LoginValidation;
import cn.middle.remote.server.NettyServer;
import cn.middle.remote.server.ServerConfig;
import cn.middle.remote.server.ServerListener;
import cn.middle.swap.dto.EdgeDto;
import cn.middle.swap.dto.EdgeServiceDto;
import cn.middle.swap.dto.RefreshEdgeDto;
import cn.middle.swap.entity.App;
import cn.middle.swap.entity.EdgeService;
import cn.middle.swap.entity.Park;
import cn.middle.swap.service.AppService;
import cn.middle.swap.service.EdgeServiceService;
import cn.middle.swap.service.ParkService;

/**
 * springboot 启动完成后，实始化netty中转服务器
 * @author KING
 *
 */
@Component
public class StartSwapServer implements CommandLineRunner {

	private final Logger logger = LoggerFactory.getLogger(this.getClass());
	@Override
	public void run(String... args) throws Exception {
		ServerConfig config = new ServerConfig();
		config.setActiveSSL(false);//是否启动ssl
		config.setPort(12039); //设置服务器端口
		config.setThreadNumber(100);
		config.setSslConfig(null);//ssl有服务配置
		Server server = new NettyServer(config);
		server.setAuthHandler(loginAuthHandler());
		server.setListener(listener());
		//server.serialization(serialization);设置序列化处理器,如果不设置，默认使用JsonSerialization 序列化处理器，如需自定义，请实现 Serialization 接口
		server.start();
	}
	
	
	private LoginAuthHandler loginAuthHandler() {
		
		return new LoginAuthHandler(){
			
			private AppService appService = ApplicationContextUtil.getBean(AppService.class);
			@Override
			public LoginValidation auth(String username, String password, Integer clientId) {
				App app = appService.login(username, password, clientId);
				if(app != null) {
					return LoginValidation.ok();
				}
				return LoginValidation.fail("该登陆信息不存在！");
			}
		};
	}
	
	/**
	 * 业务监听
	 * @return
	 */
	private ServerListener listener() {
		return new ServerListener() {
			
			Map<Integer,Integer> eventSubscribeClient = new HashMap<>();
			@Override
			public void subscribe(Integer clientId, Buffer data) {
				logger.info("{}   --> {}",clientId);
				Integer eventKey = data.to(new TypeGenericity<Integer>(){});
				eventSubscribeClient.put(eventKey, clientId);
			}
			
			@Override
			public void reply(int senderId, int targetId, String msgId, String interfaceName, Buffer data) {
				logger.info("{} --> {}",senderId, targetId);
				
			}
			
			@Override
			public void registryEdge(Integer clientId, Buffer data) {
				logger.info("{} --> {}",clientId, data);
				EdgeDto dto = data.to(new TypeGenericity<EdgeDto>(){});
				Park park = new Park();
				park.setDescription(dto.getDescribe());
				park.setParkAddress(dto.getAddress());
				park.setParkCode(dto.getEdgeId());
				park.setRemoteId(clientId);
				park.setResiterTime(dto.getRegistryTime());
				park.setParkName(dto.getEdgeName());
				ParkService parkService = ApplicationContextUtil.getBean(ParkService.class);
				Park sysPark = parkService.byParkCode(dto.getEdgeId());
				if(sysPark == null) {
					parkService.save(park);
				}else {
					park.setId(sysPark.getId());
					parkService.update(park);
				}
				
				List<EdgeServiceDto> EdgeServiceDtos = dto.getServices();
				for(EdgeServiceDto serviceDto : EdgeServiceDtos) {
					EdgeService service = new EdgeService();
					service.setParkCode(dto.getEdgeId());
					service.setRegisterTime(new Date());
					service.setServiceId(serviceDto.getServiceId());
					service.setServiceName(serviceDto.getServiceName());
					service.setServiceType(serviceDto.getServiceType());
					service.setStatus(serviceDto.getStatus());
					service.setUpdateTime(new Date());		
					
					EdgeServiceService edgeService = ApplicationContextUtil.getBean(EdgeServiceService.class);
					EdgeService sysEdgeService = edgeService.byServiceId(serviceDto.getServiceId());
					if(sysEdgeService != null) {
						service.setId(sysEdgeService.getId());
						edgeService.update(service);
					}else {
						edgeService.save(service);
					}
				}
				
			}
			
			@Override
			public void login(String username, String password, Integer clientId) {
				logger.info("{} --> {}",username, clientId);
				
			}
			
			@Override
			public void exception(Integer clientId, Throwable e) {
				logger.error(e.getMessage(),e);
				
			}
			
			@Override
			public void event(PushEventFunction functions, Integer eventId, Buffer data) {
				Integer clientId = eventSubscribeClient.get(eventId);
				if(clientId != null) {
					List<Integer> clientIds = new ArrayList<>();
					clientIds.add(clientId);
					functions.reply(clientIds, null);
				}
				
				
			}
			
			@Override
			public void edge(CallbackEvent callback, Buffer data) {
				RefreshEdgeDto dto = data.to(new TypeGenericity<RefreshEdgeDto>() {});
				Byte type = dto.getRefreshType();
				ParkService parkService = ApplicationContextUtil.getBean(ParkService.class);
				EdgeServiceService edgeService = ApplicationContextUtil.getBean(EdgeServiceService.class);
				
				List<Park> parks = new ArrayList<>();
				if(type == 0) {
					//全部同步
					parks = parkService.getAll();
				}else {
					parks = parkService.byParkCodes(dto.getParkCodes());
				}
				List<String> parkCodes = new ArrayList<>();
				parks.forEach(park -> parkCodes.add(park.getParkCode()));
				List<EdgeService> edgeServices = edgeService.listByParkCode(parkCodes);
				List<EdgeDto> edgeDtos = new ArrayList<>();
				for(Park park : parks) {
					edgeDtos.add(this.toEdgeDto(park, edgeServices));
				};
				
				callback.reply(edgeDtos);
				
			}
			
			private EdgeDto toEdgeDto(Park park,List<EdgeService> edgeServices) {
				EdgeDto dto = new EdgeDto();
				dto.setAddress(park.getParkAddress());
				dto.setClientId(park.getRemoteId());
				dto.setDescribe(park.getDescription());
				dto.setEdgeId(park.getParkCode());
				dto.setEdgeName(park.getParkName());
				List<EdgeServiceDto> serviceDtos = new ArrayList<>();
				dto.setServices(serviceDtos);
				if(edgeServices != null) {
					for(EdgeService edgeService : edgeServices) {
						if(!edgeService.getParkCode().equals(park.getParkCode())) {
							continue ;
						}
						EdgeServiceDto serviceDto = new EdgeServiceDto();
						serviceDto.setServiceId(edgeService.getServiceId());
						serviceDto.setServiceName(edgeService.getServiceName());
						serviceDto.setServiceType(edgeService.getServiceType());
						serviceDto.setStatus(edgeService.getStatus());
						serviceDtos.add(serviceDto);
					}
				}

				return dto;
			}
			
			@Override
			public void connectLost(Integer clientId) {
				logger.info("connectLost --> {} ",clientId );
				
			}
			
			@Override
			public void connectAfter(Integer clientId) {
				logger.info("connectAfter --> {} ",clientId );
				
			}
			
			@Override
			public void call(int senderId, int targetId, String msgId, String interfaceName, Buffer data) {
				logger.info("call --> {} ",senderId );
				
			}
			
			@Override
			public void ack(Integer clientId, String msgId) {
				logger.info("clientId {} --> {} ",clientId,msgId);
				
			}
		};
	}

}
